<?php
/**
 * Created by JetBrains PhpStorm.
 * User: P2DC
 * Date: 11/7/2556
 * Time: 11:37 น.
 * To change this template use File | Settings | File Templates.
 */

abstract class TbAbstract
{
    protected $_table;
    protected $_pk = 'id';
    protected static $_instance;

    protected function __construct() {}

    /**
     * @return TbAbstract
     */
    static public function instance()
    {
        if(static::$_instance == null){
            static::$_instance = new static();
        }
        $instance = static::$_instance;
        return $instance;
    }

    public function get($param = null, array $options = array())
    {
        if(!is_null($param) && empty($param))
            throw new TbException(__CLASS__.'->getOne($param) not allow empty value');

        $default = array('order'=> null, 'offset'=> null, 'limit'=> '18446744073709551615', 'offset'=> 0);
        $options = array_merge($default, $options);

        $pdo = Db::getPDO();
        $query = Helper::strTemplate("SELECT * FROM {{TABLE}}",
            array('TABLE'=> $this->_table));

        $arg = array();
        if(is_array($param)) {
            if(count($param)==0)
                throw new TbException(__CLASS__.'->getOne($param) not allow empty array');

            $i=0;
            $iIn = 0;

            foreach($param as $key => $value){
                if(is_array($value)){
                    if(!Helper::isNumericArray($value))
                        throw new TbException('where case IN can not assoc array');
                    if(count($value)==0)
                        throw new TbException('where case IN can not empty array');

                    $inArr = array();
                    foreach($value as $key2 => $value2){
                        $iIn++;
                        $inArr[] = ":keyIn{$iIn}";
                        $arg["keyIn{$iIn}"]= $value2;
                    };
                    $inArr = implode(',', $inArr);
                    $argWhere = array('key'=> $key, 'inArr'=> $inArr);
                    $impWhere = $i==0? " WHERE {{key}} IN ({{inArr}})": " AND {{key}} IN ({{inArr}})";
                    $query .= Helper::strTemplate($impWhere, $argWhere);
                }
                else{
                    $argWhere = array('key'=> $key);
                    $impWhere = $i==0? " WHERE {{key}}=:{{key}}": " AND {{key}}=:{{key}}";
                    $arg[$key] = $value;
                    $query .= Helper::strTemplate($impWhere, $argWhere);
                }
                $i++;
            }
        }
        else if(!is_null($param)) {
            $query .= Helper::strTemplate(" WHERE {{pk}}=:{{pk}}", array('pk'=> $this->_pk));
            $arg[$this->_pk] = $param;
        }

        if(!empty($options['order']))
            $query .= " ORDER BY {$options['order']}";
        if(!empty($options['limit']))
            $query .= " LIMIT {$options['limit']} OFFSET {$options['offset']}";

        $st = $pdo->prepare($query);
        $st->execute($arg);
        $item = $st->fetchAll(PDO::FETCH_ASSOC);
        return $item;
    }

    public function getOne($param, array $options = array())
    {
        $options['limit'] = 1;
        $item = $this->get($param, $options);
        if(!empty($item[0]))
            return $item[0];
        return null;
    }

    public function edit($id, $set)
    {
        $pdo = Db::getPDO();
        $query = Helper::strTemplate("UPDATE {{TABLE}} SET ", array('TABLE'=> $this->_table));
        $buff = array();
        $params = array();
        foreach($set as $key => $value){
            $field = Db::escape($key, Db::ESCAPE_FIELD);
            $buff[] = sprintf("%s=:%s", $field, $field);
            $params[$field] = $value;
        }
        $params['id'] = $id;
        $query .= implode(',', $buff);
        $query .= " WHERE ".$this->_pk."=:id";
        $pdo->prepare($query)
            ->execute($params);
    }

    public function del($param)
    {
        $pdo = Db::getPDO();
        $arg = array();
        $query = Helper::strTemplate("DELETE FROM {{TABLE}}", array('TABLE'=> $this->_table));
        if(is_array($param)){
            if(count($param)==0)
                throw new TbException(__CLASS__.'->del($param) not allow empty array');

            $i = 0;
            $iIn = 0;
            foreach($param as $key => $value){
                if(is_array($value)){
                    if(!Helper::isNumericArray($value))
                        throw new TbException('where case IN can not assoc array');
                    if(count($value)==0)
                        throw new TbException('where case IN can not empty array');

                    $inArr = array();
                    foreach($value as $key2 => $value2){
                        $iIn++;
                        $inArr[] = ":keyIn{$iIn}";
                        $arg["keyIn{$iIn}"]= $value2;
                    };
                    $inArr = implode(',', $inArr);
                    $argWhere = array('key'=> $key, 'inArr'=> $inArr);
                    $impWhere = $i==0? " WHERE {{key}} IN ({{inArr}})": " AND {{key}} IN ({{inArr}})";
                    $query .= Helper::strTemplate($impWhere, $argWhere);
                }
                else{
                    $argWhere = array('key'=> $key);
                    $impWhere = $i==0? " WHERE {{key}}=:{{key}}": " AND {{key}}=:{{key}}";
                    $arg[$key] = $value;
                    $query .= Helper::strTemplate($impWhere, $argWhere);
                }
                $i++;
            }
            $pdo->prepare($query)
                ->execute($arg);
        }
        else {
            $query .= " WHERE id=:id";
            $arg["id"] = $param;
        }
        $pdo->prepare($query)
            ->execute($arg);
    }

    public function add(array $data = array())
    {
        $pdo = Db::getPDO();

        $fields = array();
        $criteria = array();
        $attr = array();
        foreach($data as $key => $value){
            $field = Db::escape($key, Db::ESCAPE_FIELD);
            $fields[] = $field;
            $criteria[] = ':'.$field;
            $attr[$field] = $value;
        }
        $fields = implode(',', $fields);
        $criteria = implode(',', $criteria);

        $query = Helper::strTemplate("INSERT INTO {{TABLE}}({{fields}}) VALUES({{criteria}})",
        array('TABLE'=> $this->_table, 'fields'=> $fields, 'criteria'=> $criteria));

        $pdo->prepare($query)
            ->execute($attr);
    }
}

class TbException extends Exception{}

/*
 * $startInt = (int)$start;
 * $limitInt = (int)$limit == 0? '18446744073709551615': (int)$limit;
 */